<?php
/**
 * Base model class that all our models will inherit from.
 *
 * The main purpose of the base model is to provide models with a way
 * of handling their resources.
 *
 * @package Custom_Model
 * @version $Id$
 */
abstract class Custom_Model_Repositories_RepositoryAbstract 
        implements Custom_Model_RepositoryInterface
{
    /**
     * @var array Class methods
     */
    protected $_classMethods;

    /**
     * @var array validation instances
     */
    protected $_validates = array();
    
    /**
     * @var array entity resource instances
     */
    protected $_resources = array();

    /**
     * @var array error messages
     */
    protected $_messages = array();
    
    /**
     * Class contructor
     *
     * @param Zend_Config|array|null $option
     * @return Custom_Model_Abstract
     */
    public function __construct($option = null)
    {
        $this->_classMethods = get_class_methods($this);

        if ($option instanceof Zend_Config) {
            $option = $option->toArray();
        }

        if (is_array($option)) {
            $this->setOptions($option);
        }

        $this->init();
    }

    /**
     * Constructor extensions
     */
    public function init()
    {
    }

    /**
     * Set options using setter methods
     *
     * @param array $option Configuration array
     * @return Custom_Model_Abstract
     */
    public function setOptions(array $option)
    {
        foreach ($option as $key => $val) {
            $method = 'set' . ucfirst(strtolower($key));
            if (in_array($method, $this->_classMethods)) {
                $this->$method($val);
            }
        }

        return $this;
    }

    /**
     *
     * Get properties of a class
     * @param class $class
     * @return array propertyArray
     */
    protected function _getProperties($class)
    {
        $propertyArray = array();
        $refClass = new Zend_Reflection_Class($class);
        $properties = $refClass->getProperties();
        foreach ($properties as $property) {
            if ($property->isPublic()) {
                $propertyArray[] = $property->getName();
            }
        }
        return $propertyArray;
    }


    /**
     * Retreive a validation object such as Zend_Form
     *
     * Implement a service container pattern to receive a real object
     *
     * @param string $name Name of validation
     * @return Zend_Validate_Interface
     * @throws Custom_Model_Exception
     */
    public function getValidate($name)
    {
        $class = join('_', array(
            $this->_getNamespace(),
            'Model',
            $name
        ));
        if (!class_exists($class)) {
            $class = $name;
        }
        if (!isset($this->_validates[$class])) {
            if (!class_exists($class)) {
                throw new Custom_Model_Exception("Validator '" . $class . "' is not declared yet.");
            }
            $this->_validates[$name] = new $class();
        }
	    return $this->_validates[$name];
    }

     /**
     * Retreive a resource object such as Zend_Db_Table
     *
     * Implement a service container pattern to receive a real object
     *
     * @param string $name Name of entity resource
     * @return Custom_Model_EntityInterface
     * @throws Custom_Model_Exception
     */
    public function getResource($name)
    {
        $class = join('_', array(
            $this->_getNamespace(),
            'Model',
            'Entities',
            $name
        ));
        if (!class_exists($class)) {
            $class = $name;
        }
        if (!isset($this->_resources[$class])) {
            if (!class_exists($class)) {
                throw new Custom_Model_Exception("Resource '" . $class . "' is not declared yet.");
            }
            $this->_resources[$name] = new $class();
        }
	    return $this->_resources[$name];
    }
    
    
    /**
     * Classes are named spaced using their module name
     * this returns that module name or the first class name segment.
     *
     * @return string This class namespace
     */
    private function _getNamespace()
    {
        $ns = explode('_', get_class($this));
        return $ns[0];
    }

	/**
     * Retreive error messages if any
     * 
     * @return array
     */
    public function getMessages()
    {
        return $this->_messages;
    }
    
    /**
     * Set error messages if any
     * To clear the error message container, ignore $messages parameter
     * 
     * @param array $messages
     * @return string
     */
    public function setMessages($messages = null)
    {
        // clear error messages
        if (null === $messages) {
            $this->_messages = array();
        }
        
        if (is_object($messages)) {
            $messages = $message->toArray();
        }
        
        if (!is_array($messages)) {
            $messages = array($messages);
        }
        
        $this->_messages = array_merge($this->_messages, $messages);
        return $this->_messages;
    }

}